package main

import (
	"context"
	"encoding/json"
	"io"
	"net/http"
	"time"

	"gitee.com/jason_elva8325/apigw-quickstart/common"
	"gitee.com/jason_elva8325/apigw-quickstart/config"
	"gitee.com/jason_elva8325/apigw-quickstart/pb"
	"github.com/afex/hystrix-go/hystrix"
	"github.com/go-kit/kit/circuitbreaker"
	"github.com/go-kit/kit/endpoint"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/sd"
	"github.com/go-kit/kit/sd/etcdv3"
	"github.com/go-kit/kit/sd/lb"
	"github.com/gorilla/mux"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
)

func init() {}

func main() {}

// AdapterRegistry 适配器注册方法，方法名及参数不能修改，否则无法注册
func AdapterRegistry(router *mux.Router, logger log.Logger, client etcdv3.Client, srdPrefix string, adapters map[string]config.Adapter) {
	// 获取适配器配置
	cbc := hystrix.CommandConfig{}
	var prefixURI, version string

	if cbs, ok := adapters["say-goodby-grpc"]; ok {
		prefixURI = cbs.PrefixURI
		version = cbs.Version
		if cb, ok := cbs.Hystries["hystrix"]; ok {
			cbc.Timeout = cb.Timeout
			cbc.SleepWindow = cb.SleepWindow
			cbc.ErrorPercentThreshold = cb.ErrorPercentThreshold
			cbc.MaxConcurrentRequests = cb.MaxConcurrentRequests
			cbc.RequestVolumeThreshold = cb.RequestVolumeThreshold
		}
	}

	router.HandleFunc("/"+version+prefixURI+"/goodby/{lang}", func(w http.ResponseWriter, r *http.Request) {
		// 声明最终返回对象
		var httpResponse = common.GenericResponse{}

		// 解析HTTP请求
		vars := mux.Vars(r)
		lang, ok := vars["lang"]
		if !ok {
			return
		}
		target := r.URL.Query().Get("target")

		//创建实例例管理理器器, 此管理理器器会Watch监听etc中prefix的⽬目录变化更更新缓存的服务实例例数据
		instancer, err := etcdv3.NewInstancer(client, srdPrefix+"Say/GRPC/", logger)
		if err != nil {
			logger.Log("Service watcher on ETCD server create fail", err, "sessionid", r.Header.Get("Sessionid"))
			return
		}
		//创建端点管理理器器， 此管理理器器根据Factory和监听的到实例例创建endPoint并订阅instancer的变化
		endpointer := sd.NewEndpointer(instancer, func(instanceAddr string) (endpoint.Endpoint, io.Closer, error) {
			return func(ctx context.Context, request interface{}) (interface{}, error) {
				logger.Log("grpc dail up addr", instanceAddr, "sessionid", r.Header.Get("Sessionid"))

				conn, err := grpc.Dial(instanceAddr, grpc.WithInsecure(), grpc.WithTimeout(time.Second))
				if err != nil {
					logger.Log("grpc dail error", err, "sessionid", r.Header.Get("Sessionid"))
					return nil, err
				}
				defer conn.Close()

				// 追加sessionid到GRPC的metadata信息中，并返回修改后的context，用于服务链路追踪
				ctx = metadata.AppendToOutgoingContext(ctx, "sessionid", r.Header.Get("Sessionid"))

				client := pb.NewSayServiceClient(conn)
				rs, err := client.SayGoodby(ctx, &pb.SayGoodbyRequest{
					Lang:   lang,
					Target: target,
				})
				if err != nil {
					logger.Log("Function", "SayGoodby", "Execute", "fail", "sessionid", r.Header.Get("Sessionid"))
					return nil, err
				}
				logger.Log("Function", "SayGoodby", "Execute", "success", "sessionid", r.Header.Get("Sessionid"))
				return rs, nil
			}, nil, nil
		}, logger)
		//创建负载均衡器器
		balancer := lb.NewRoundRobin(endpointer)
		reqEndPoint := lb.Retry(2, 3*time.Second, balancer)
		//创建服务熔断
		// 可通过关闭服务端予以测试
		commandName := "my-endpoint"
		hystrix.ConfigureCommand(commandName, cbc)
		reqEndPoint = circuitbreaker.Hystrix(commandName)(reqEndPoint)
		//通过 endPoint 发起请求
		ereq := struct{}{}
		eres, err := reqEndPoint(context.Background(), ereq)
		if err != nil {
			logger.Log("Backend service call fail", err, "sessionid", r.Header.Get("Sessionid"))
			httpResponse.Err = err.Error()
			w.WriteHeader(http.StatusExpectationFailed)
		} else {
			w.WriteHeader(http.StatusOK)
		}
		httpResponse.V = eres
		// 返回HTTP结果
		json.NewEncoder(w).Encode(&httpResponse)
	}).Methods("GET")

	logger.Log("Loaded adapter", "say-goodby-"+version)
}
